#include "PLVec2.h"
#include "PLDataTypes.h"

#include <math.h>

const PLuint X = 0U;
const PLuint Y = 1U;

/**
  *	Constructs a new PLVec2<T> object with the given arguments
  *
  * @param x first element of the vector
  * @param y second element of the vector
  */
template <typename T>
PLVec2<T>::PLVec2( const T &x, const T &y )
{
	mVec[X] = x;
	mVec[Y] = y;
}

/**
  *	Returns a PLVec2<T> object, that is a normal vector to this vector, calculated
  * by rotating this vector clockwise.
  *
  * @return cw-normal vector to this vector
  */
template <typename T>
PLVec2<T> PLVec2<T>::GetCWNormal( void ) const
{
	return PLVec2<T>( mVec[Y], -mVec[X] );
}

/**
  *	Normalizes the vector by dividing all elements by the length of the vector
  * When the vector has length 0, nothing happens.
  *
  * @return const reference to this pointer after normalization
  */
template <typename T>
const PLVec2<T> &PLVec2<T>::Normalize( void )
{
	T length = sqrt( (mVec[X] * mVec[X]) + (mVec[Y] * mVec[Y]) );

	if (0.0 != length)
	{
		mVec[X] /= length;
		mVec[Y] /= length;
	}

	return *this;
}

/**
  *	Returns the first element of the vector, which is the X-coordinate
  *
  * @return first element of the vector, which is the X-coordinate
  */
template <typename T>
const T &PLVec2<T>::GetX( void ) const
{
	return mVec[X];
}

/**
  *	Returns the second element of the vector, which is the Y-coordinate
  *
  * @return second element of the vector, which is the Y-coordinate
  */
template <typename T>
const T &PLVec2<T>::GetY( void ) const
{
	return mVec[Y];
}

/**
  *	Overlaoded + operator for the PLVec2<T> class. Returns a vector that is
  * the sum of this and the given vector
  *
  * @param vec vector that is added to this one
  * @return PLVec2<T> object that is the sum of this and the given vector
  */
template <typename T>
PLVec2<T> PLVec2<T>::operator+( const PLVec2<T> &vec ) const
{
	return PLVec2<T>(mVec[X] + vec.mVec[X], mVec[Y] + vec.mVec[Y]);
}

/**
  *	Overlaoded * operator for the PLVec2<T> class. Returns a vector that is
  * this vector scaled by the given factor
  *
  * @param mult scale factor
  * @return PLVec2<T> object that is this vector scaled by the given factor
  */
template <typename T>
PLVec2<T> PLVec2<T>::operator*( const double &mult ) const
{
	return PLVec2<T>( mVec[X] * mult, mVec[Y] * mult );
}

/**
  *	Overloaded [] operator for the PLVec2<T> class.
  *
  * @param index index of the desired element
  * @return reference to the element at index index
  */
template <typename T>
T &PLVec2<T>::operator[]( const PLuint &index )
{
	return mVec[index];
}

/**
  *	Overloaded [] operator for the PLVec2<T> class.
  *
  * @param index index of the desired element
  * @return const reference to the element at index index
  */
template <typename T>
const T &PLVec2<T>::operator[]( const PLuint &index ) const
{
	return mVec[index];
}

template class PLVec2<double>;